xc_shadow_control_stats_t *stats);
-#define XCFLAGS_VERBOSE 1
-#define XCFLAGS_LIVE 2
-#define XCFLAGS_DEBUG 4
+#define XCFLAGS_VERBOSE 1
+#define XCFLAGS_LIVE 2
+#define XCFLAGS_DEBUG 4
+#define XCFLAGS_CONFIGURE 8
struct XcIOContext;
int xc_linux_save(int xc_handle, struct XcIOContext *ioctxt);
}
shared_info_frame = op.u.getdomaininfo.shared_info_frame;
+ if(ioctxt->flags & XCFLAGS_CONFIGURE)
+ {
+ if(xcio_configure_domain(ioctxt))
+ {
+ xcio_error(ioctxt, "Configuring domain failed");
+ goto out;
+ }
+ }
+
if ( (pm_handle = init_pfn_mapper((domid_t)dom)) == NULL )
goto out;
@param id: domain id
@param notify: send a domain died event if true
"""
- for info in self.domain_by_name.values():
+ for (k, info) in self.domain_by_name.items():
if info.id == id:
- del self.domain_by_name[info.name]
+ del self.domain_by_name[k]
if id in self.domain_by_id:
info = self.domain_by_id[id]
del self.domain_by_id[id]
@return: deferred
"""
- def cbok(dominfo):
- self._add_domain(dominfo)
- return dominfo
- deferred = XendDomainInfo.vm_restore(src, progress=progress)
- deferred.addCallback(cbok)
+ if 0:
+ def cbok(dominfo):
+ self._add_domain(dominfo)
+ return dominfo
+ deferred = XendDomainInfo.vm_restore(src, progress=progress)
+ deferred.addCallback(cbok)
+ else:
+ xmigrate = XendMigrate.instance()
+ deferred = xmigrate.restore_begin(src)
return deferred
def domain_get(self, id):
eserver.inject('xend.domain.migrate',
[ self.dominfo.name, self.dominfo.id,
"begin", self.sxpr() ])
- # Special case for localhost: destroy all devices early.
- if 0 and self.dst_host in ["localhost", "127.0.0.1"]:
- self.dominfo.restart_cancel()
- self.dominfo.cleanup()
- #self.dominfo.destroy_console()
xfrd.request(['xfr.migrate',
self.src_dom,
vmconfig,
self.dst_port,
self.live ])
+ def xfr_vm_suspend(self, xfrd, val):
+ def cbok(val):
+ # Special case for localhost: destroy devices early.
+ if self.dst_host in ["localhost", "127.0.0.1"]:
+ self.dominfo.restart_cancel()
+ self.dominfo.cleanup()
+ self.dominfo.destroy_console()
+ return val
+
+ d = XfrdInfo.xfr_vm_suspend(self, xfrd, val)
+ d.addCallback(cbok)
+ return d
+
def xfr_migrate_ok(self, xfrd, val):
dom = int(sxp.child0(val))
self.state = 'ok'
[ self.dominfo.name, self.dominfo.id,
self.state, self.sxpr() ])
+class XendRestoreInfo(XfrdInfo):
+ """Representation of a restore in-progress and its interaction with xfrd.
+ """
+
+ def __init__(self, xid, file):
+ XfrdInfo.__init__(self)
+ self.xid = xid
+ self.state = 'begin'
+ self.file = file
+
+ def sxpr(self):
+ sxpr = ['restore',
+ ['id', self.xid],
+ ['file', self.file] ]
+ return sxpr
+ def request(self, xfrd):
+ print '***request>', self.file
+ log.info('restore BEGIN: ' + str(self.sxpr()))
+ xfrd.request(['xfr.restore', self.file ])
+
+ def xfr_restore_ok(self, xfrd, val):
+ dom = int(sxp.child0(val))
+ dominfo = self.xd.domain_get(dom)
+ self.state = 'ok'
+ if not self.deferred.called:
+ self.deferred.callback(dominfo)
+
+
class XendMigrate:
"""External api for interaction with xfrd for migrate and save.
Singleton.
info = XendSaveInfo(xid, dominfo, file)
return self.session_begin(info)
+ def restore_begin(self, file):
+ xid = self.nextid()
+ info = XendRestoreInfo(xid, file)
+ return self.session_begin(info)
+
+
def instance():
global inst
try:
/** Receive domain state.
* Create a new domain and store the received state into it.
*/
-int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n){
+int xen_domain_rcv(IOStream *io,
+ uint32_t *dom,
+ char **vmconfig, int *vmconfig_n,
+ int *configured){
int err = 0;
#ifdef _XEN_XFR_STUB_
char buf[1024];
ioctxt->info = iostdout;
ioctxt->err = iostderr;
ioctxt->configure = domain_configure;
+ ioctxt->flags |= XCFLAGS_CONFIGURE;
err = xc_linux_restore(xcinit(), ioctxt);
*dom = ioctxt->domain;
*vmconfig = ioctxt->vmconfig;
*vmconfig_n = ioctxt->vmconfig_n;
+ *configured = (ioctxt->flags & XCFLAGS_CONFIGURE);
#endif
dprintf("< err=%d\n", err);
return err;
uint32_t dom,
char *vmconfig, int vmconfig_n,
int live);
-extern int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n);
+extern int xen_domain_rcv(IOStream *io,
+ uint32_t *dom,
+ char **vmconfig, int *vmconfig_n,
+ int *configured);
extern int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n);
Sxpr oxfr_migrate; // (xfr.migrate <vmid> <vmconfig> <host> <port> <live>)
Sxpr oxfr_migrate_ok;// (xfr.migrate.ok <value>)
Sxpr oxfr_progress; // (xfr.progress <percent> <rate: kb/s>)
+Sxpr oxfr_restore; // (xfr.restore <file>)
+Sxpr oxfr_restore_ok;// (xfr.restore.ok <vmid>)
Sxpr oxfr_save; // (xfr.save <vmid> <vmconfig> <file>)
Sxpr oxfr_save_ok; // (xfr.save.ok)
Sxpr oxfr_vm_destroy;// (xfr.vm.destroy <vmid>)
oxfr_migrate = intern("xfr.migrate");
oxfr_migrate_ok = intern("xfr.migrate.ok");
oxfr_progress = intern("xfr.progress");
+ oxfr_restore = intern("xfr.restore");
+ oxfr_restore_ok = intern("xfr.restore.ok");
oxfr_save = intern("xfr.save");
oxfr_save_ok = intern("xfr.save.ok");
oxfr_vm_destroy = intern("xfr.vm.destroy");
return (err < 0 ? err : 0);
}
+int xfr_send_restore_ok(Conn *conn, uint32_t vmid){
+ int err = 0;
+
+ err = IOStream_print(conn->out, "(%s %d)",
+ atom_name(oxfr_restore_ok), vmid);
+ return (err < 0 ? err : 0);
+}
+
int xfr_send_save_ok(Conn *conn){
int err = 0;
return err;
}
+/** Restore a vm from file.
+ *
+ * @return 0 on success, error code otherwise
+ */
+int xfr_restore(Args *args, XfrState *state, Conn *xend, char *file){
+ int err = 0;
+ IOStream *io = NULL;
+ int configured=0;
+
+ dprintf("> file=%s\n", file);
+ io = gzip_stream_fopen(file, "rb");
+ if(!io){
+ eprintf("> Failed to open %s\n", file);
+ err = -EINVAL;
+ goto exit;
+ }
+ err = xen_domain_rcv(io,
+ &state->vmid_new,
+ &state->vmconfig, &state->vmconfig_n,
+ &configured);
+ if(err) goto exit;
+ if(!configured){
+ err = xen_domain_configure(state->vmid_new, state->vmconfig, state->vmconfig_n);
+ if(err) goto exit;
+ }
+ err = xen_domain_unpause(state->vmid_new);
+ exit:
+ if(io){
+ IOStream_close(io);
+ IOStream_free(io);
+ }
+ if(err){
+ xfr_error(xend, err);
+ } else {
+ xfr_send_restore_ok(xend, state->vmid_new);
+ }
+ dprintf("< err=%d\n", err);
+ return err;
+}
+
/** Accept the transfer of a vm from another node.
*
* @param peer connection
int err = 0;
time_t t0 = time(NULL), t1;
Sxpr sxpr;
+ int configured=0;
dprintf(">\n");
- err = xen_domain_rcv(peer->in, &state->vmid_new, &state->vmconfig, &state->vmconfig_n);
+ err = xen_domain_rcv(peer->in,
+ &state->vmid_new,
+ &state->vmconfig, &state->vmconfig_n,
+ &configured);
if(err) goto exit;
// Read from the peer. This is just so we wait before configuring.
// When migrating to the same host the peer must destroy the domain
// before we configure the new one.
err = Conn_sxpr(peer, &sxpr);
if(err) goto exit;
- err = xen_domain_configure(state->vmid_new, state->vmconfig, state->vmconfig_n);
- if(err) goto exit;
+ if(!configured){
+ err = xen_domain_configure(state->vmid_new, state->vmconfig, state->vmconfig_n);
+ if(err) goto exit;
+ }
err = xen_domain_unpause(state->vmid_new);
if(err) goto exit;
// Report new domain id to peer.
if(err) goto exit;
err = xfr_save(args, state, conn, file);
+ } else if(sxpr_elementp(sxpr, oxfr_restore)){
+ // Restore message from xend.
+ char *file;
+ XfrState _state = {}, *state = &_state;
+ int n = 0;
+
+ dprintf("> xfr.restore\n");
+ err = stringof(sxpr_childN(sxpr, n++, ONONE), &file);
+ if(err) goto exit;
+ err = xfr_restore(args, state, conn, file);
+
} else if(sxpr_elementp(sxpr, oxfr_xfr)){
// Xfr message from peer xfrd.
XfrState _state = {}, *state = &_state;